package com.apes.scm.stock.transfer.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.soe.metadata.Scene;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.Stock;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.stock.transfer.model.ConsumableUse;
import com.apes.scm.stock.transfer.model.ConsumableUseItem;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.PickItem;
import com.apes.scm.stock.transfer.repository.ConsumableUseRepository;
import com.apes.scm.stock.transfer.repository.PickRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 功能：APP出入库接口
 *
 * @author LJP
 * @create 2021-07-15 10:02
 */
@Service("pickAppService")
public class PickAppService extends DomainService {

    @Autowired
    private PickRepository pickRepository;
    @Autowired
    private ConsumableUseRepository consumableUseRepository;
    @Autowired
    private LocationRepository locationRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private PurchaseOrderRepository purchaseOrderRepository;


    /**
     * 出库--搜索单据(带id)/出库--扫码查询交货单（带id）
     * @param request
     * @return
     */
    public JSONArray findPick(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "confirmed", "deliver");
        return convertPick(pickList);
    }

    /**
     * 查询全部可出库交货单(分页)
     * @param request
     * @return
     * @throws Exception
     */
    public Page findPickDeliver(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "confirmed", "deliver");
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        if (pickList.size() == 0) return new PageImpl<>(new ArrayList<>(), pageable, 0);
        return new PageImpl<>(convertPick(autoPage(request,pickList)), pageable, pickList.size());
    }

    /**
     * 查询全部可入库交货单
     * @param request
     * @return
     * @throws Exception
     */
    public JSONArray findPickReceipt(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "confirmed", "receipt");
        return convertPick(pickList);
    }


    /**
     * 查询全部可入库交货单(分页)
     * @param request
     * @return
     * @throws Exception
     */
    public Page findPickReceiptPage(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "confirmed", "receipt");
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        if (pickList.size() == 0) return new PageImpl<>(new ArrayList<>(), pageable, 0);
        return new PageImpl<>(convertPick(autoPage(request,pickList)), pageable, pickList.size());
    }

    /**
     * 出库记录--交货单
     * @param request
     * @return
     */
    public Page findDeliver(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "done", "deliver");
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        if (pickList.size() == 0) return new PageImpl<>(new ArrayList<>(), pageable, 0);
        return new PageImpl<>(convertPick(autoPage(request,pickList)), pageable, pickList.size());
    }

    /**
     * 入库记录--交货单
     * @param request
     * @return
     */
    public JSONArray findReceipt(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "done", "receipt");
        return convertPick(pickList);
    }

    /**
     * 入库记录--交货单（分页）
     * @param request
     * @return
     */
    public Page findReceiptPage(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "done", "receipt");
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        if (pickList.size() == 0) return new PageImpl<>(new ArrayList<>(), pageable, 0);
        return new PageImpl<>(convertPick(autoPage(request,pickList)), pageable, pickList.size());
    }

    /**
     * 出库记录--耗材领用单
     * @param request
     * @return
     */
    public Page findDeliverConsumableUse(SimpleRequest request) throws Exception {
        List<ConsumableUse> consumableUseList = getConsumableUseList(request);
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        if (consumableUseList.size() == 0) return new PageImpl<>(new ArrayList<>(), pageable, 0);
        return new PageImpl<>(convertConsumableUse(autoPage(request,consumableUseList)), pageable, consumableUseList.size());
    }


    /**
     * 出库记录--搜索单据
     * @param request
     * @return
     */
    public JSONArray findDeliverById(SimpleRequest request) throws Exception {
        List<Pick> pickList = getPickList(request, "done", "deliver");
        List<ConsumableUse> consumableUseList = getConsumableUseList(request);
        JSONArray jsonArray = new JSONArray();
        if (pickList!=null) jsonArray.addAll(convertPick(pickList));
        if (consumableUseList != null)jsonArray.addAll(convertConsumableUse(consumableUseList));
        return jsonArray;
    }

    /**
     * 出库--耗材领用单扫码商品
     * @param request
     * @return
     */
    public JSONObject findConsumProduct(SimpleRequest request) {
        JSONObject param = request.getJO();
        String productId = param.getString("productId");
        String locationId = param.getString("locationId");
        Product product = productRepository.findOne(productId);
        if (product == null) throw new RuntimeException("查询不到该商品:"+productId);
        if (!product.isFreeSuppliesValid()) throw new RuntimeException("该商品不是耗材商品！！");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("productId",product.getId());
        jsonObject.put("productName",product.getName());
        jsonObject.put("uom",product.getUom().getName());
        Stock stock = SpringManager.getBean(StockRepository.class).findAll(JpaDsl.toCriteriaByEq("location.id", locationId, "product.id", productId)).get(0);
        jsonObject.put("qty",stock.getUsableQty() - stock.getFrozenQty());//可领用数量 = 库存账可用数 - 冻结数
        return jsonObject;
    }

    /**
     * 出库--交货单扫码商品
     * @param request
     * @return
     */
    public JSONObject findPickProduct(SimpleRequest request) {
        JSONObject param = request.getJO();
        String pickId = param.getString("pickId");
        String productId = param.getString("productId");
        Pick pick = pickRepository.findOne(pickId);
        if (pick == null) throw new RuntimeException("查询不到该交货单:"+pickId);
        if ("done".equals(pick.getState())) throw new RuntimeException("该交货单已完成");
        boolean flag = pick.getPickItems().stream().anyMatch(pickItem -> productId.equals(pickItem.getProduct().getId()));
        if (!flag) throw new RuntimeException("该商品和交货单没有关联");
        Product product = productRepository.findOne(productId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("productId",product.getId());
        jsonObject.put("productName",product.getName());
        jsonObject.put("uom",product.getUom().getName());
        return jsonObject;
    }

    /**
     * 交货单出库/交货单入库
     * @param request
     * @return
     */
    public JSONObject disposePick(SimpleRequest request) {
        JSONObject param = request.getJO();
        String pickId = param.getString("pickId");
        String operatorId = param.getString("operatorId");
        JSONArray items = param.getJSONArray("items");

        Pick pick = pickRepository.findOne(pickId);
        if (pick==null) throw new RuntimeException("查询不到该交货单："+pickId);
        if (!"confirmed".equals(pick.getState())) throw new RuntimeException("该交货单已交货，请重新查询操作！");
        String type = pick.getMoveType().getId();

        checkPick(items,pick);

        PartyRole doneUid = partyRoleRepository.findOne(operatorId);
        if (doneUid == null) throw new RuntimeException("找不到该操作人："+operatorId);
        pick.setDoneUid(doneUid);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id",pick.getId());
        jsonObject.put("pickItems",items);
        jsonObject.put("version",pick.getVersion());
        pick = invoke("stock.pick.delivery",jsonObject);
        return convertOnePick(pick);
    }

    public void checkPick(JSONArray items,Pick pick) {
        if (pick.getMoveType().getId().equals("direct")) return;
        if (items.size() != pick.getPickItems().size()) throw new RuntimeException("该交货单是一次性交货，不能部分交货");
        for (int i = 0; i < items.size(); i++) {
            JSONObject item = (JSONObject)items.get(i);
            List<PickItem> pickItems = pick.getPickItems().stream().filter(pickItem -> String.valueOf(pickItem.getId()).equals(item.getString("id"))).collect(Collectors.toList());
            if (pickItems.size() ==0) throw new RuntimeException("该交货单找不到该明细" + item.getString("id"));
            if (pickItems.get(0).getProductUomQty() != item.getDoubleValue("qtyDone")) throw new RuntimeException("该交货单是一次性交货，不能部分交货");
        }
    }

    public JSONArray convertPick(List<Pick> pickList) {
        JSONArray result = new JSONArray();
        pickList.stream().forEach(pick -> {
            JSONObject jsonObject = convertOnePick(pick);
            result.add(jsonObject);
        });
        return result;
    }

    public JSONObject convertOnePick(Pick pick) {
        PartyRole creator = new PartyRole();
        if (pick.getCreator()!= null) creator = partyRoleRepository.findOne(pick.getCreator());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("operation",pick.getOperation().equals("deliver")?"发货":"收货");
        jsonObject.put("deptId",pick.getLocation().getDept().getName());
        jsonObject.put("id",pick.getId());
        jsonObject.put("type","交货");
        jsonObject.put("origin",pick.getOrigin());
        jsonObject.put("originName",pick.getOriginBusinessTypeName());
        jsonObject.put("partnerId",pick.getReceiptLocation()==null?"":pick.getReceiptLocation().getId());
        jsonObject.put("partnerName",pick.getReceiptLocation()==null?"":pick.getReceiptLocation().getName());
        jsonObject.put("locationId",pick.getLocation().getId());
        jsonObject.put("locationName",pick.getLocation().getName());
        jsonObject.put("creator",pick.getDoneUid()!=null?pick.getDoneUid().getName():"");
        jsonObject.put("createDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(pick.getCreateDate()));
        if (pick.getDateDone()!=null) jsonObject.put("doneDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(pick.getDateDone()));
        if ("RetailOrder".equals(pick.getOriginBusinessType())){
            String str = JSONObject.toJSONString(invoke("retail.order.findOne", mapper("id",pick.getOrigin())));
            String carLicense =  JSONObject.parseObject(str).getJSONObject("customerExpand").getString("carLicense");
            jsonObject.put("carId",carLicense);
        }
        //明细
        JSONArray array = new JSONArray();
        pick.getPickItems().forEach(pickItem -> {
            JSONObject item = new JSONObject();
            item.put("id",pickItem.getId());
            item.put("productId",pickItem.getProduct().getId());
            item.put("productName",pickItem.getProduct().getName());
            item.put("qty",pickItem.getProductUomQty());//待出库数
            item.put("doneQty",pickItem.getQtyDone());//出库数
            item.put("uom",pickItem.getUom().getName());
            array.add(item);
        });
        jsonObject.put("items",array);
        return jsonObject;
    }

    public JSONObject convertOneConsumableUse(ConsumableUse consumableUse) {
        PartyRole creator = new PartyRole();
        if (consumableUse.getCreator()!= null) creator = partyRoleRepository.findOne(consumableUse.getCreator());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id",consumableUse.getId());
        jsonObject.put("deptId",consumableUse.getLocation().getDept().getName());
        jsonObject.put("operation","耗材领用");
        jsonObject.put("type","耗材");
        jsonObject.put("locationId",consumableUse.getLocation().getId());
        jsonObject.put("locationName",consumableUse.getLocation().getName());
        jsonObject.put("creator",creator.getName());
        jsonObject.put("createDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(consumableUse.getDateCreate()));
        if (consumableUse.getDateDone()!=null) jsonObject.put("doneDate",consumableUse.getDateDone().toString());
        //明细
        JSONArray array = new JSONArray();
        consumableUse.getConsumableUseItems().forEach(consumableUseItem -> {
            JSONObject item = new JSONObject();
            item.put("id",consumableUseItem.getId());
            item.put("productId",consumableUseItem.getProduct().getId());
            item.put("productName",consumableUseItem.getProduct().getName());
            item.put("qty",consumableUseItem.getUseQty());//领用数
            item.put("uom",consumableUseItem.getUom().getName());
            array.add(item);
        });
        jsonObject.put("items",array);
        return jsonObject;
    }

    public JSONArray convertConsumableUse(List<ConsumableUse> consumableUseList) {
        JSONArray result = new JSONArray();
        consumableUseList.stream().forEach(consumableUse -> {
            JSONObject jsonObject = convertOneConsumableUse(consumableUse);
            result.add(jsonObject);
        });
        return result;
    }

    public List<Pick> getPickList(SimpleRequest request,String state,String operation) throws Exception {
        JSONObject param = request.getJO();
        String deptId = param.getString("deptId");
        String id = param.getString("id");
        String startDate = param.getString("startDate");
        String endDate = param.getString("endDate");

        List<Map> condition = new ArrayList<>();
        condition.add(mapper("field","location.depot.dept.id","value",deptId,"operator","EQ"));
        condition.add(mapper("field","operation","value",operation,"operator","EQ"));
        condition.add(mapper("field","state","value",state,"operator","EQ"));

        if (startDate != null && endDate != null) {
            SimpleDateFormat spdf = new SimpleDateFormat("yyyy-MM-dd");
            Date start = spdf.parse(startDate);
            Date end = spdf.parse(endDate);
            condition.add(mapper("field","dateDone","value",start,"operator","GT"));
            condition.add(mapper("field","dateDone","value",addDay(end),"operator","LT"));
        }
        List<Pick> pickList = pickRepository.findAll(JpaDsl.toCriteria(condition));
        if (id != null) {
            List<Pick> purchaseOrderList = pickList.stream().filter(e -> e.getOriginBusinessType().equals("PurchaseOrder")).collect(Collectors.toList());
            if (id.length() == 4) {
                purchaseOrderList = purchaseOrderList.stream().filter(e->{
                    PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(e.getOrigin());
                    if (purchaseOrder.getOrigin() != null && id.equals(purchaseOrder.getOrigin().substring(purchaseOrder.getOrigin().length() - 4))) return true;
                    if (purchaseOrder.getSupplierRef() != null && id.equals(purchaseOrder.getSupplierRef().substring(purchaseOrder.getSupplierRef().length() - 4))) return true;
                    if (purchaseOrder.getSource() != null && id.equals(purchaseOrder.getSource().substring(purchaseOrder.getSource().length() - 4))) return true;
                    return false;
                }).collect(Collectors.toList());

                List<Pick> origin = pickList.stream().filter(e -> id.equals(e.getOrigin().substring(e.getOrigin().length() - 4))).collect(Collectors.toList());
                pickList = pickList.stream().filter(e-> id.equals(e.getId().substring(e.getId().length()-4))).collect(Collectors.toList());
                if (origin.size()!=0)pickList.addAll(origin);
                if (purchaseOrderList.size()!=0)pickList.addAll(purchaseOrderList);
            }else {
                purchaseOrderList = purchaseOrderList.stream().filter(e->{
                    PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(e.getOrigin());
                    if (purchaseOrder.getOrigin() != null && id.equals(purchaseOrder.getOrigin())) return true;
                    if (purchaseOrder.getSupplierRef() != null && id.equals(purchaseOrder.getSupplierRef())) return true;
                    if (purchaseOrder.getSource() != null && id.equals(purchaseOrder.getSource())) return true;
                    return false;
                }).collect(Collectors.toList());
                List<Pick> origin = pickList.stream().filter(e -> id.equals(e.getOrigin())).collect(Collectors.toList());
                pickList = pickList.stream().filter(e-> id.equals(e.getId())).collect(Collectors.toList());
                if (origin.size()!=0)pickList.addAll(origin);
                if (purchaseOrderList.size()!=0)pickList.addAll(purchaseOrderList);
            }

        }
        return pickList;
    }

    /**
     * App创建耗材领用单并审核（耗材领用单出库）
     * @param request
     * @return
     */
    public JSONObject createConsumableUse(SimpleRequest request) {
        JSONObject param = request.getJO();
        ConsumableUse consumableUse = new ConsumableUse();
        Location location = locationRepository.findOne(param.getString("locationId"));
        PartyRole creator = partyRoleRepository.findOne(request.get("creator").toString());
        if (creator == null) throw new RuntimeException("ERP找不到该制单人");
        Enumeration enumeration = new Enumeration();
        enumeration.setId("one");
        Scene scene = new Scene();
        scene.setId("HC000");

        consumableUse.setLocation(location);
        consumableUse.setCompany(location.getCompany());
        consumableUse.setDept(location.getDept());
        consumableUse.setClerk(creator);
        consumableUse.setNote("APP耗材领用出库");
        consumableUse.setMoveType(enumeration);
        consumableUse.setScene(scene);
        consumableUse.setCreator(creator.getId());

        JSONArray items = request.getJO().getJSONArray("items");
        Set<ConsumableUseItem> consumableUseItems = new HashSet();
        for (int i = 0; i < items.size(); i++) {
            JSONObject item = items.getJSONObject(i);
            Product product = productRepository.findOne(item.getString("productId"));
            if (product == null) throw new RuntimeException("查询不到商品：ID【"+item.getString("productId")+"】");

            ConsumableUseItem consumableUseItem = new ConsumableUseItem();
            consumableUseItem.setCompany(location.getCompany());
            consumableUseItem.setConsumableUse(consumableUse);
            consumableUseItem.setProduct(product);
            consumableUseItem.setUom(product.getUom());
            consumableUseItem.setUseQty(Double.valueOf(item.getString("qty")));
            consumableUseItems.add(consumableUseItem);
        }

        consumableUse.setConsumableUseItems(consumableUseItems);

        consumableUse = invoke("consumableuse.order.create", JSONObject.parseObject(JSONObject.toJSONString(consumableUse))); //新增
        consumableUse = invoke("consumableuse.order.approve", mapper("id",consumableUse.getId(),"version",consumableUse.getVersion())); //审批
        return convertOneConsumableUse(consumableUse);
    }

    /**
     * 根据门店查询仓库
     * @param request
     * @return
     */
    public JSONArray getLocations(SimpleRequest request) {
        JSONObject param = request.getJO();
        String deptId = param.getString("deptId");
        String name = param.getString("name");
        List<Location> locationList = locationRepository.findAll(JpaDsl.toCriteriaByEq("depot.dept.id",deptId,"valid",true));
        if (locationList.isEmpty()) throw new RuntimeException("该门店["+deptId+"]没有配置仓库");
        if (name != null)locationList = locationList.stream().filter(location -> location.getName().contains(name)).collect(Collectors.toList());

        JSONArray array = new JSONArray();
        locationList.forEach(location -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("locationId",location.getId());
            jsonObject.put("locationName",location.getName());
            array.add(jsonObject);
        });

        return array;
    }

    public List<ConsumableUse> getConsumableUseList(SimpleRequest request) throws Exception {
        JSONObject param = request.getJO();
        String deptId = param.getString("deptId");
        String id = param.getString("id");
        String startDate = param.getString("startDate");
        String endDate = param.getString("endDate");

        List<Map> condition = new ArrayList<>();
        condition.add(mapper("field","dept.id","value",deptId,"operator","EQ"));
        condition.add(mapper("field","state","value","done","operator","EQ"));
        if (startDate != null && endDate != null) {
            SimpleDateFormat spdf = new SimpleDateFormat("yyyy-MM-dd");
            Date start = spdf.parse(startDate);
            Date end = spdf.parse(endDate);
            condition.add(mapper("field","dateDone","value",start,"operator","GT"));
            condition.add(mapper("field","dateDone","value",addDay(end),"operator","LT"));
        }
        List<ConsumableUse> consumableUseList = consumableUseRepository.findAll(JpaDsl.toCriteria(condition));

        if (id != null) {
            if (id.length() == 4) {
                consumableUseList = consumableUseList.stream().filter(e-> id.equals(e.getId().substring(e.getId().length()-4))).collect(Collectors.toList());
            }else {
                condition.add(mapper("field","id","value",id,"operator","EQ"));
                return consumableUseRepository.findAll(JpaDsl.toCriteria(condition));
            }
        }
        return consumableUseList;
    }

    /**
     * 入库--扫码单据入库(带Id)/入库搜索（带Id）
     * @param request
     * @return
     */
    public JSONArray getStorageById(SimpleRequest request) throws Exception {
        JSONArray jsonArray = new JSONArray();
        JSONArray productReceives = invoke("stock.productReceive.findAllReturn", mapper("id",request.get("id").toString(),"deptId",request.get("deptId").toString()));
        JSONArray picks = findPickReceipt(request);
        if (productReceives != null) jsonArray.addAll(productReceives);
        if (picks != null) jsonArray.addAll(picks);
        return jsonArray;
    }

    /**
     * 入库记录--搜索单据
     * @param request
     * @return
     */
    public JSONArray getReceiptById(SimpleRequest request) throws Exception {
        JSONArray jsonArray = new JSONArray();
        JSONArray picks = findReceipt(request);
        JSONArray productReceives = invoke("stock.productReceive.getProductReturns", mapper("id",request.get("id").toString(),"deptId",request.get("deptId").toString()));
        if (!picks.isEmpty()) jsonArray.addAll(picks);
        if (!productReceives.isEmpty()) jsonArray.addAll(productReceives);
        return jsonArray;
    }


    /**
     * CompletableFuture 示例：异步查询
     * @param request
     * @return
     * @throws Exception
     */
    public JSONObject countQtyAsync(SimpleRequest request) throws Exception {
        JSONObject param = request.getJO();
        String deptId = param.getString("deptId");
        String start = param.getString("startDate");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date startDate = sdf.parse(start);

        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(startDate);
        rightNow.add(Calendar.MONTH, 1);
        Date endDate = rightNow.getTime();

        /* 异步查询任务 */
        CompletableFuture findDeliverPickTask = CompletableFuture.supplyAsync(() -> findDonePick(deptId, "deliver", startDate, endDate));
        CompletableFuture findReceiptPickTask = CompletableFuture.supplyAsync(() -> findDonePick(deptId, "receipt", startDate, endDate));
        CompletableFuture findConsumableTask = CompletableFuture.supplyAsync(() -> findDoneConsumableUse(deptId, startDate, endDate));

        Map queryParam = MapUtil.mapper("deptId", deptId, "startDate", startDate, "endDate", endDate);
        CompletableFuture findProductReceiveTask = CompletableFuture.supplyAsync(() -> invoke("stock.productReceive.findProductReturnQty", queryParam));
        CompletableFuture findProductReturnTask = CompletableFuture.supplyAsync(() -> invoke("stock.productReceive.findProductReceiveQty", queryParam));

        // 异步任务组合
        CompletableFuture deliverQtyFuture = findDeliverPickTask.thenCombine(findConsumableTask, (pickDeliverQty, consumableUseQty) -> (double) pickDeliverQty + (double) consumableUseQty);
        CompletableFuture receiptQtyFuture = findReceiptPickTask.thenCombine(findProductReceiveTask, (pickReceiptQty, productReturnQty) -> (double) pickReceiptQty + (double) productReturnQty);

        double deliverQty = (double) deliverQtyFuture.get();
        double receiptQty = (double) receiptQtyFuture.get();
        double receiveQty = (double) findProductReturnTask.get();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("deliverQty", deliverQty);
        jsonObject.put("receiptQty", receiptQty);
        jsonObject.put("receiveQty", receiveQty);
        return jsonObject;
    }


    /**
     * 出入库情况
     * @param request
     * @return
     */
    public JSONObject countQty(SimpleRequest request) throws Exception{
        JSONObject param = request.getJO();
        String deptId = param.getString("deptId");
        String start = param.getString("startDate");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Date startDate = sdf.parse(start);

        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(startDate);
        rightNow.add(Calendar.MONTH, 1);
        Date endDate = rightNow.getTime();
        //出库数量
        double pickDeliverQty = findDonePick(deptId, "deliver", startDate, endDate);
        double consumableUseQty = findDoneConsumableUse(deptId, startDate, endDate);
        //入库数量
        double pickReceiptQty = findDonePick(deptId,"receipt",startDate,endDate);
        double qty = invoke("stock.productReceive.findProductReturnQty", MapUtil.mapper("deptId", deptId, "startDate", startDate, "endDate", endDate));
        //领用数量
        double receiveQty = invoke("stock.productReceive.findProductReceiveQty", MapUtil.mapper("deptId", deptId, "startDate", startDate, "endDate", endDate));

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("deliverQty",pickDeliverQty + consumableUseQty);
        jsonObject.put("receiptQty",pickReceiptQty + qty);
        jsonObject.put("receiveQty",receiveQty);
        return jsonObject;
    }

    private double findDonePick(String deptId, String operation, Date startDate, Date endDate) {
        Map map = pickRepository.findDonePick(deptId, operation, startDate, endDate);
        if (map.size() == 0 ) return 0.0;
        return Double.parseDouble(map.get("qtyDone").toString());
    }

    private double findDoneConsumableUse(String deptId,  Date startDate, Date endDate) {
        Map map = consumableUseRepository.findDone(deptId, startDate, endDate);
        if (map.size() ==0 ) return 0.0;
        return Double.parseDouble(map.get("useQty").toString());
    }

    public JSONObject findDoneAll(SimpleRequest request) {
        String deptId = request.getJO().getString("deptId");
        int consumableSize = consumableUseRepository.findAll(JpaDsl.toCriteriaByEq("dept.id",deptId,"state","done")).size();
        int deliverSize = pickRepository.findAll(JpaDsl.toCriteriaByEq("location.depot.dept.id",deptId,"state","done","operation","deliver")).size();
        int receiptSize = pickRepository.findAll(JpaDsl.toCriteriaByEq("location.depot.dept.id",deptId,"state","done","operation","receipt")).size();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("consumableSize",consumableSize);
        jsonObject.put("deliverSize",deliverSize);
        jsonObject.put("receiptSize",receiptSize);
        return jsonObject;
    }

    public JSONObject findCanPickQty(SimpleRequest request) {
        String deptId = request.getJO().getString("deptId");
        int deliverQty = pickRepository.findAll(JpaDsl.toCriteriaByEq("location.depot.dept.id",deptId,"state","confirmed","operation","deliver")).size();
        int receiptQty = pickRepository.findAll(JpaDsl.toCriteriaByEq("location.depot.dept.id",deptId,"state","confirmed","operation","receipt")).size();
        int waitReceiveQty = waitReceiveQty(deptId);
        int waitReturunQty = invoke("stock.productReceive.waitReturunQty", mapper("deptId", deptId));

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("deliverQty",deliverQty);
        jsonObject.put("receiptQty",receiptQty);
        jsonObject.put("waitReceiveQty",waitReceiveQty);
        jsonObject.put("waitReturunQty",waitReturunQty);
        return jsonObject;
    }

    public int waitReceiveQty(String deptId) {
        JSONObject result = new JSONObject(invoke("fn.service.waitReceiveList", mapper("deptId", deptId)));
        return result.getInteger("waitReceiveQty");
    }

    public List autoPage(SimpleRequest request, List list) {
        int page = request.getJO().getInteger("page");
        int size = request.getJO().getInteger("size");
        List result = new ArrayList<>();
        if (list.size() <= size*(page +1)) {
            result  = list.subList(page*size,list.size());
        }else {
            result  = list.subList(page*size,size*(page +1));
        }
        return result;
    }

    public Date addDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE,1);
        return cal.getTime();
    }
}
